using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.Resources;
using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
using Microsoft.BizTalk.Component;
using Microsoft.BizTalk.Messaging;
using System.Text.RegularExpressions;

namespace eliasen.eu.BizTalk.PipelineComponents
{    
    
    [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    [Guid("4b8cd6de-18b3-4c74-8dc4-6397febc39d9")]
    [ComponentCategory(CategoryTypes.CATID_Any)]
    public class SearchAndReplace : Microsoft.BizTalk.Component.Interop.IComponent, IBaseComponent, IPersistPropertyBag, IComponentUI
    {

        private System.Resources.ResourceManager resourceManager = Util.GetResourceManager();

        #region Properties

        private bool _UseRegularExpressions;
        
        public bool UseRegularExpressions
        {
            get
            {
                return _UseRegularExpressions;
            }
            set
            {
                _UseRegularExpressions = value;
            }
        }
        
        private string _Search;
        
        public string Search
        {
            get
            {
                return _Search;
            }
            set
            {
                _Search = value;
            }
        }
        
        private string _Replace;
        
        public string Replace
        {
            get
            {
                return _Replace;
            }
            set
            {
                _Replace = value;
            }
        }

        #endregion

        #region IBaseComponent members
        /// <summary>
        /// Name of the component
        /// </summary>
        [Browsable(false)]
        public string Name
        {
            get
            {
                return resourceManager.GetString("SearchAndReplace_Name", System.Globalization.CultureInfo.InvariantCulture);
            }
        }
        
        /// <summary>
        /// Version of the component
        /// </summary>
        [Browsable(false)]
        public string Version
        {
            get
            {
                return resourceManager.GetString("SearchAndReplace_Version", System.Globalization.CultureInfo.InvariantCulture);
            }
        }
        
        /// <summary>
        /// Description of the component
        /// </summary>
        [Browsable(false)]
        public string Description
        {
            get
            {
                return resourceManager.GetString("SearchAndReplace_Description", System.Globalization.CultureInfo.InvariantCulture);
            }
        }
        #endregion
        
        #region IPersistPropertyBag members
        /// <summary>
        /// Gets class ID of component for usage from unmanaged code.
        /// </summary>
        /// <param name="classid">
        /// Class ID of the component
        /// </param>
        public void GetClassID(out System.Guid classid)
        {
            classid = new System.Guid("4b8cd6de-18b3-4c74-8dc4-6397febc39d9");
        }
        
        /// <summary>
        /// not implemented
        /// </summary>
        public void InitNew()
        {
        }
        
        /// <summary>
        /// Loads configuration properties for the component
        /// </summary>
        /// <param name="pb">Configuration property bag</param>
        /// <param name="errlog">Error status</param>
        public virtual void Load(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, int errlog)
        {
            object val = null;
            val = this.ReadPropertyBag(pb, "UseRegularExpressions");
            if ((val != null))
            {
                this._UseRegularExpressions = ((bool)(val));
            }
            val = this.ReadPropertyBag(pb, "Search");
            if ((val != null))
            {
                this._Search = ((string)(val));
            }
            val = this.ReadPropertyBag(pb, "Replace");
            if ((val != null))
            {
                this._Replace = ((string)(val));
            }
        }
        
        /// <summary>
        /// Saves the current component configuration into the property bag
        /// </summary>
        /// <param name="pb">Configuration property bag</param>
        /// <param name="fClearDirty">not used</param>
        /// <param name="fSaveAllProperties">not used</param>
        public virtual void Save(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, bool fClearDirty, bool fSaveAllProperties)
        {
            this.WritePropertyBag(pb, "UseRegularExpressions", this.UseRegularExpressions);
            this.WritePropertyBag(pb, "Search", this.Search);
            this.WritePropertyBag(pb, "Replace", this.Replace);
        }
        
        #region utility functionality
        /// <summary>
        /// Reads property value from property bag
        /// </summary>
        /// <param name="pb">Property bag</param>
        /// <param name="propName">Name of property</param>
        /// <returns>Value of the property</returns>
        private object ReadPropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName)
        {
            object val = null;
            try
            {
                pb.Read(propName, out val, 0);
            }
            catch (System.ArgumentException )
            {
                return val;
            }
            catch (System.Exception e)
            {
                throw new System.ApplicationException(e.Message);
            }
            return val;
        }
        
        /// <summary>
        /// Writes property values into a property bag.
        /// </summary>
        /// <param name="pb">Property bag.</param>
        /// <param name="propName">Name of property.</param>
        /// <param name="val">Value of property.</param>
        private void WritePropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName, object val)
        {
            try
            {
                pb.Write(propName, ref val);
            }
            catch (System.Exception e)
            {
                throw new System.ApplicationException(e.Message);
            }
        }
        #endregion
        #endregion
        
        #region IComponentUI members
        /// <summary>
        /// Component icon to use in BizTalk Editor
        /// </summary>
        [Browsable(false)]
        public IntPtr Icon
        {
            get
            {
                return new System.IntPtr();
                //return ((System.Drawing.Bitmap)(this.resourceManager.GetObject("COMPONENTICON", System.Globalization.CultureInfo.InvariantCulture))).GetHicon();
            }
        }
        
        /// <summary>
        /// The Validate method is called by the BizTalk Editor during the build 
        /// of a BizTalk project.
        /// </summary>
        /// <param name="obj">An Object containing the configuration properties.</param>
        /// <returns>The IEnumerator enables the caller to enumerate through a collection of strings containing error messages. These error messages appear as compiler error messages. To report successful property validation, the method should return an empty enumerator.</returns>
        public System.Collections.IEnumerator Validate(object obj)
        {
            // example implementation:
            // ArrayList errorList = new ArrayList();
            // errorList.Add("This is a compiler error");
            // return errorList.GetEnumerator();
            return null;
        }
        #endregion
        
        #region IComponent members
        /// <summary>
        /// Implements IComponent.Execute method.
        /// </summary>
        /// <param name="pc">Pipeline context</param>
        /// <param name="inmsg">Input message</param>
        /// <returns>Original input message</returns>
        /// <remarks>
        /// IComponent.Execute method is used to initiate
        /// the processing of the message in this pipeline component.
        /// </remarks>
        public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
        {
            Stream inStream = inmsg.BodyPart.Data;
            
            StreamReader reader = new StreamReader(inmsg.BodyPart.Data);
            string messageBody = reader.ReadToEnd();

            if (UseRegularExpressions)
            {
                Regex crlf = new Regex(Search, RegexOptions.Multiline);
                messageBody = crlf.Replace(messageBody, Replace);
            }
            else
            {
                messageBody = messageBody.Replace(Search, Replace);
            }
            byte[] firstString = System.Text.Encoding.UTF8.GetBytes(messageBody);
            
            MemoryStream outStream = new MemoryStream();
            outStream.Write(firstString, 0, firstString.Length);
            outStream.Seek(0, SeekOrigin.Begin);
            inmsg.BodyPart.Data = outStream;
            pc.ResourceTracker.AddResource(outStream);
            return inmsg;
        }
        #endregion
    }
}
